home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Various
/
DevDisk 65 (1989)(DevWare PD).zip
/
DevDisk 65 (1989)(DevWare PD).adf
/
ifflib
/
ShowIFF
/
ShowIFF.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-11
|
22KB
|
624 lines
/*************************************************************************
** **
** ShowIFF - a comfortable IFF file viewer for CLI and WorkBench **
** **
** All known formats (including Overscan, HAM, HalfBrite, SHAM) are **
** supported. If a picture is larger than the screen, you may use the **
** mouse to scroll around (If you have enough CHIP memory...) **
** **
** This program and iff.library by: Chris Weber **
** Bruggerweg 2 **
** CH-8037 Zürich **
** SWITZERLAND **
** (BIX: chw) **
** **
** Any suggestions or bug reports are welcome! **
** **
**************************************************************************
** **
** This program is in the Public Domain. Use it at your own risk. **
** **
** Requirements: - arp.library V39+ **
** - iff.library V18+ **
** **
** To compile: - Lattice C compiler V5.04 or above (use 32bit ints) **
** - The file 'arpstartup.o' (My ARP startup module) **
** - The file 'arpglue.lib' for Printf etc. **
** **
**************************************************************************
** **
** WorkBench usage: **
** --------------- **
** **
** Select all pictures you wish to see while pressing the SHIFT key, **
** then double-click on the ShowIFF icon. **
** You can also set the picture's default tool to 'ShowIFF' using the **
** WorkBench 'Info' feature. **
** If you wish to display all the pictures in a drawer, select the **
** drawer and then the ShowIFF icon. This works even with disk icons! **
** If a drawer or disk contains another drawer, the pictures in that **
** drawer will also be displayed. **
** **
** **
** CLI usage: **
** --------- **
** **
** ShowIFF [files] [DELAY delay in seconds] [LOOP] [ALL] [NOBREAK] **
** [NOOVERSCAN] **
** **
** Example: ShowIFF Lo-Res/Pic* Hi-Res/foo RAM:*.pic DELAY 5 ALL **
** **
** [files] can be any number of file names, directories or disk names. **
** All of the ARP wildcards can be used. (?,*,#?,...) **
** **
** [DELAY] specifies the delay between two pictures in seconds. If not **
** specified, this is set to infinity. Note that you can always go **
** to the next picture by pressing the left mouse button. **
** **
** [LOOP] if specified, repeatedly displays all the pictures, which is **
** useful for creating slide-shows or other demos. **
** **
** [ALL] if specified, pictures in sub-directories will also be **
** displayed. **
** **
** [NOBREAK] disabled the breaking features described below **
** **
** [NOOVERSCAN] display all pictures in normal mode, and never in **
** overscan. This is useful if you want to see every pixel... **
** **
** **
** Keys and mouse-buttons: **
** ---------------------- **
** **
** While a picture is displayed, you can **
** **
** - press the left mouse button, which will display the next picture **
** **
** - press the right mouse button, which will abort the program **
** **
** - press Ctrl-C (if the ShowIFF window or the CLI window is active) **
** which will abort the ShowIFF program **
** **
** - press Ctrl-E (if the ShowIFF window or the CLI window is active) **
** which will quit the current directory and return to the **
** parent-directory (only in conjunction with the 'ALL' option) **
** **
** - move the mouse, the picture will scroll if it is larger than the **
** screen. Note that HAM pictures may have distortions on the **
** left side. This is a hardware limitation of the HAM mode. **
** **
**************************************************************************
** **
** Modification History: **
** -------------------- **
** **
** 15-Oct-87 CHW V1.0 Created this file! **
** 30-Jun-88 CHW V1.4 Directory scan fixed for FFS, cleaned up **
** 16-Nov-88 CHW V1.5 Overscan implemented **
** 28-Nov-88 CHW V1.6 Minimal screen size is now 64x64 pixels **
** 02-Jan-89 CHW V1.7 Double-buffering implemented **
** 25-Sep-89 CHW V2.01 Changed to Lattice C and ARP library **
** 27-Sep-89 CHW V2.02 Screen scrolling implemented **
** 22-Nov-89 CHW V2.03 Rejects Non-ILBM files correctly **
** 21-Feb-90 CHW V2.04 'NoMemForGfx' bug fixed, overscan fixed **
** 28-Feb-90 CHW V2.10 SHAM support code added **
** 14-Mar-90 CHW V2.11 Memory fragmentation workaround, cleanup **
** 08-Apr-90 CHW V2.12 Pics with more than 6 planes don't guru **
** **
*************************************************************************/
#include <proto/exec.h>
#include <exec/memory.h>
#include <arp/arpbase.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <hardware/custom.h>
#include <libraries/iff.h> /* Not an official CBM file (yet?:-) */
#include <workbench/startup.h>
#include <string.h>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define reg register /* My favorite alias */
struct MyAnchor
{
struct AnchorPath APath;
char FullPath[255]; /* cheap way to extend ap_Buf[] */
};
struct Picture
{
struct Screen *Screen; /* The picture's screen */
struct Window *Window; /* The invisible window for mouse handling */
struct BitMap BitMap; /* CustomBitMap, may be larger than screen */
WORD MaxX0,MaxY0; /* Scrolling limits */
};
char StdWindowName[] = "CON:0/12/640/82/ShowIFF V2.12 08-Apr-90 by Christian A. Weber";
char CLI_Template[] = "Patterns/...,D=DELAY/k,L=LOOP/s,ALL/s,NB=NOBREAK/s,NO=NOOVERSCAN/s";
char CLI_Help[] = "ShowIFF V2.12 08-Apr-90 by Christian A. Weber\n"
"Usage: ShowIFF [files or patterns] [DELAY delay] [LOOP] [ALL]\n"
"\t\t[NOBREAK] [NOOVERSCAN]";
#define ARG_PATTERN 0 /* Argument numbers for GADS() */
#define ARG_DELAY 1
#define ARG_LOOP 2
#define ARG_ALL 3
#define ARG_NOBREAK 4
#define ARG_NOOVERSCAN 5
#define ARG_INVALID 6
#define NUMARGS (ARG_INVALID+1)
extern void exit(LONG); /* My startup code's exit function */
extern struct Library *ArpBase; /* Also used for DOS functions */
extern struct Library *IntuitionBase; /* Opened by ArpStartup */
extern struct GfxBase *GfxBase; /* Opened by ArpStartup */
struct Library *IFFBase; /* That's the big one! */
extern struct Custom __far custom; /* For SSHAM copper list */
BOOL WorkBench;
LONG WBDelay=3145728; /* keep window open for 3 seconds*/
struct Picture pic1,pic2; /* 2 pictures for double-buffering */
IFFFILE ifffile;
WORD *emptysprite;
LONG delay = 0x100000; /* Default parameters for WB */
BOOL loop = FALSE;
BOOL all = TRUE;
BOOL nobreak = FALSE;
BOOL overscan = TRUE;
/*************************************************************************/
void ZeroMem(reg UBYTE *adr,reg LONG len)
{
while(--len>=0) *adr++=0;
}
/*************************************************************************/
/* Free all planes of a bitmap */
void FreeBitMap(reg struct BitMap *bm)
{
reg LONG planesize=bm->BytesPerRow*(bm->Rows+8),i;
for(i=0; i<bm->Depth; ++i)
if(bm->Planes[i])
{
FreeMem(bm->Planes[i],planesize);
bm->Planes[i]=0;
}
}
/*************************************************************************/
/* Initialize a BitMap structure and allocate CHIP memory for the planes */
BOOL AllocBitMap(reg struct BitMap *bm,LONG d,LONG w,LONG h)
{
reg LONG planesize,i;
InitBitMap(bm,d,w,h);
planesize=bm->BytesPerRow*(bm->Rows+8);
for(i=0; i<d; ++i)
if(!(bm->Planes[i]=AllocMem(planesize,MEMF_CHIP|MEMF_CLEAR)))
{
FreeBitMap(bm);
return FALSE;
}
return TRUE;
}
/*************************************************************************/
/* Adjust the X/Y position of a screen for correct overscan display */
void SetOverscan(struct Screen *screen)
{
reg WORD rows,x=screen->Width,y=screen->Height;
reg struct ViewPort *vp=&(screen->ViewPort);
rows = GfxBase->NormalDisplayRows; if(rows>300) rows>>=1;
x -= 320; if(vp->Modes & HIRES) x -= 320;
y -= rows; if(vp->Modes & LACE) y -= rows;
x >>=1; if(x<0) x=0; y >>=1; if(y<0) y=0; if(y>40) y=40;
if(vp->Modes & HAM) /* Correct overscan HAM color distortions */
{
if(GfxBase->ActiView->DxOffset-x < 96)
x=GfxBase->ActiView->DxOffset-96;
}
vp->DxOffset = -x; vp->DyOffset = -y;
MakeScreen(screen); RethinkDisplay();
}
/*************************************************************************/
/* Make SHAM copper list if this is an SHAM picture */
void MakeSHAM(struct Picture *pic)
{
reg LONG i,j,step=(pic->Screen->ViewPort.Modes&LACE)?2:1;
reg WORD copx=GfxBase->ActiView->DxOffset+pic->Screen->Width;
reg struct UCopList *ucop=AllocMem(sizeof(struct UCopList),MEMF_CLEAR);
reg struct SHamChunk
{
struct Chunk Chunk;
UWORD Version;
UWORD Colors[1024][16];
} *shamck;
if(ucop && (shamck=FindChunk(ifffile,ID_SHAM)))
{
if(shamck->Version == 0)
{
Printf("SHAM ");
for(i=1; i<MIN(pic->Screen->Height,shamck->Chunk.ckSize>>5); ++i)
{
CWAIT(ucop,(i-1)*step,(UWORD)((copx>>1)%(UWORD)228))
for(j=1; j<16; ++j) CMOVE(ucop,custom.color[j],shamck->Colors[i][j])
}
CEND(ucop)
pic->Screen->ViewPort.UCopIns = ucop; RemakeDisplay();
}
else Printf("Unsupported SHAM mode: %ld",(LONG)shamck->Version);
}
}
/*************************************************************************/
/* Free a picture (that is a window, screen and a custom BitMap) */
void ClosePicture(reg struct Picture *pic)
{
if(pic->Window)
{
ScreenToBack(pic->Screen);
ClearPointer(pic->Window);
CloseWindow(pic->Window);
pic->Window=0;
}
if(pic->Screen)
{
CloseScreen(pic->Screen);
pic->Screen=0;
}
FreeBitMap(&pic->BitMap);
RemakeDisplay(); /* remake copperlist to increase MEMF_LARGEST */
}
/*************************************************************************/
/* Allocate a picture (Allocate custom BitMap, open screen and window) */
BOOL OpenPicture(reg struct Picture *pic,reg struct BitMapHeader *bmhd)
{
reg WORD xov=64,yov=40; /* Maximal overscan values for LoRes */
struct NewScreen ns;
struct NewWindow nw;
UWORD colortable[512];
ClosePicture(pic);
ZeroMem((UBYTE *)&ns,sizeof(ns));
ZeroMem((UBYTE *)&nw,sizeof(nw));
ns.Width = 320; /* Minimal width */
ns.Height = GfxBase->NormalDisplayRows; /* Minimal height */
ns.Depth = MAX(bmhd->nPlanes,1);
ns.ViewModes = (UWORD)GetViewModes(ifffile);
ns.Type = CUSTOMSCREEN|CUSTOMBITMAP|SCREENQUIET|SCREENBEHIND;
ns.CustomBitMap = &pic->BitMap;
if(ns.ViewModes & HIRES) { ns.Width <<= 1; xov <<= 1; }
if(ns.ViewModes & LACE) { ns.Height <<= 1; yov <<= 1; }
if(overscan)
{
if((bmhd->w > ns.Width) && (bmhd->w <= (ns.Width+xov)))
ns.Width = bmhd->w;
if((bmhd->h > ns.Height) && (bmhd->h <= (ns.Height+yov)))
ns.Height = bmhd->h;
}
if(AllocBitMap(&pic->BitMap,(LONG)bmhd->nPlanes,
MAX(bmhd->w,ns.Width),MAX(bmhd->h,ns.Height)))
{
if(nw.Screen=pic->Screen=OpenScreen(&ns))
{
if(ns.Depth>6)
{
pic->Screen->BitMap.Depth=ns.ViewModes & HIRES ? 4:5;
RemakeDisplay();
}
nw.Width = ns.Width;
nw.Height = ns.Height;
nw.IDCMPFlags = MOUSEBUTTONS|MOUSEMOVE|DELTAMOVE;
nw.Flags = BACKDROP|BORDERLESS|ACTIVATE|SIMPLE_REFRESH
|NOCAREREFRESH|REPORTMOUSE|RMBTRAP;
nw.Type = CUSTOMSCREEN;
if(pic->Window=OpenWindow(&nw))
{
reg long count;
pic->MaxX0=bmhd->w-ns.Width;
pic->MaxY0=bmhd->h-ns.Height;
SetPointer(pic->Window,emptysprite,1L,16L,0L,0L);
if(!(count=GetColorTab(ifffile,colortable)))
{
/* Provide default colors for pictures without a CMAP */
count=2; colortable[0]=0xeca; colortable[1]=0x000;
}
if(count>32) count = 32; /* Fix old DigiView pictures */
LoadRGB4(&(pic->Screen->ViewPort),colortable,count);
SetOverscan(pic->Screen);
return TRUE;
}
}
}
ClosePicture(pic);
return FALSE;
}
/*************************************************************************/
/* Close all resources and exit to CLI/WorkBench */
void Fail(reg char *reason)
{
Printf("%s\n",reason);
ClosePicture(&pic1); ClosePicture(&pic2);
if(ifffile) { CloseIFF(ifffile); ifffile=0; }
if(emptysprite) { FreeMem(emptysprite,20); emptysprite=0; }
if(IFFBase) { CloseLibrary(IFFBase); IFFBase=0; }
if(WorkBench) WaitForChar(Input(),WBDelay); /* Let them see our text */
exit(0L); /* Back to the startup code (important for WorkBench) */
}
/*************************************************************************/
/* This gets called if the user hits ^C or sends us a BREAK signal */
__stdargs void _abort(void)
{
Fail("\n***BREAK - ShowIFF terminated.");
}
/************************************************************************/
/* That's the big one! Load & display a picture (with mouse-scrolling) */
void ShowPicture(reg char *name)
{
if(!strcmp(name+strlen(name)-5,".info")) return; /* Skip icons */
Printf("%s ... ",name);
if(ifffile) CloseIFF(ifffile);
if(ifffile=OpenIFF(name))
{
if(*(((ULONG *)ifffile)+2) == ID_ILBM)
{
reg struct BitMapHeader *bmhd;
if(bmhd=GetBMHD(ifffile))
{
Printf("%ld x %ld x %ld ",bmhd->w,bmhd->h,bmhd->nPlanes);
retry: if(OpenPicture(&pic1,bmhd))
{
if(DecodePic(ifffile,&pic1.BitMap))
{
reg LONG i;
reg WORD xoff=0,yoff=0;
MakeSHAM(&pic1);
ScreenToFront(pic1.Screen);
ClosePicture(&pic2);
for(i=delay*50L; i>=0; --i)
{
reg struct IntuiMessage *msg;
WaitTOF();
while(msg=(struct IntuiMessage *)GetMsg(pic1.Window->UserPort))
{
if(msg->Class == MOUSEMOVE)
{
xoff+=msg->MouseX;
if(xoff>pic1.MaxX0) xoff=pic1.MaxX0;
if(xoff<0) xoff=0;
yoff+=msg->MouseY;
if(yoff>pic1.MaxY0) yoff=pic1.MaxY0;
if(yoff<0) yoff=0;
pic1.Screen->ViewPort.RasInfo->RxOffset=xoff;
pic1.Screen->ViewPort.RasInfo->RyOffset=yoff;
/* ScrollVPort(&pic1.Screen->ViewPort); */
MakeScreen(pic1.Screen); RethinkDisplay();
}
else if(!nobreak)
{
if(msg->Code == SELECTDOWN) goto showend;
else if(msg->Code == MENUDOWN) _abort();
}
ReplyMsg((struct Message *)msg);
}
if(!nobreak) CheckAbort(_abort);
}
showend: pic2=pic1; ZeroMem((UBYTE *)&pic1,sizeof(pic1));
Puts(" - Done");
}
else
{
ClosePicture(&pic1);
Printf("- Decode error: %ld\n",IFFError());
}
}
else if(pic2.Window)
{
ClosePicture(&pic2); goto retry;
}
else Puts("- Can't open screen!");
}
else Printf("- Mangled IFF file (%ld)\n",IFFError());
}
else Puts("- not an ILBM file!");
}
else Puts("- not an IFF file!");
}
/************************************************************************/
/* Expand a pattern and call ShowPicture() for each matching file */
void ShowPattern(char *pathname)
{
reg BPTR file;
char buf[256];
if(PreParse(pathname,buf)) /* TRUE if name contains any wildcards */
{
reg struct MyAnchor *myanchor;
iswild:
if(myanchor=ArpAlloc(sizeof(struct MyAnchor)))
{
reg BOOL showit=TRUE;
reg LONG error;
myanchor->APath.ap_StrLen = 255; /* Want full path built */
myanchor->APath.ap_Flags = APF_DOWILD;
myanchor->APath.ap_BreakBits=SIGBREAKF_CTRL_C;
error=FindFirst(pathname,&myanchor->APath);
while(!error)
{
/* +1 because of a lattice bug */
if(SetSignal(0L,SIGBREAKF_CTRL_E+1) & SIGBREAKF_CTRL_E)
{
Puts("***DIR BREAK"); showit=FALSE;
/* myanchor->APath.ap_Flags &= ~APF_DODIR; */
}
if(myanchor->APath.ap_Info.fib_DirEntryType>=0) /* Dir */
{
if(all)
{
if(!(myanchor->APath.ap_Flags & APF_DIDDIR))
{
myanchor->APath.ap_Flags |= APF_DODIR;
showit=TRUE;
}
myanchor->APath.ap_Flags &= ~APF_DIDDIR;
}
}
else if(showit) ShowPicture(myanchor->APath.ap_Buf);
error=FindNext(&myanchor->APath);
}
FreeAnchorChain(&myanchor->APath);
switch(error)
{
case ERROR_BREAK: _abort(); break;
case ERROR_OBJECT_NOT_FOUND: Puts("File not found."); break;
case ERROR_BUFFER_OVERFLOW: Puts("Path too long!"); break;
case ERROR_NO_MORE_ENTRIES: break; /* Normal termination */
default: Printf("IO error %ld!\n",error); break;
}
}
else Fail("No mem for anchor!");
}
else if(file=Open(pathname,MODE_OLDFILE)) /* Just a file ? */
{
Close(file); ShowPicture(pathname); return;
}
else /* No wildcards, and not a file: it's a device or a directory */
{
strcpy(buf,pathname); TackOn(pathname=buf,"*");
goto iswild; /* Not really elegant, but it works */
}
}
/************************************************************************/
/* Main program: parse the command line or WorkBench-args */
void ARPMain(LONG arglen,reg char *argline)
{
WorkBench=(arglen==0);
emptysprite=AllocMem(20L,MEMF_CHIP|MEMF_CLEAR);
if(!(IFFBase = OpenLibrary(IFFNAME,0L))) Fail("No iff.library!");
if(IFFBase->lib_Version < IFFVERSION)
Printf("WARNING: you have an old version of iff.library!\n");
if(arglen) /* From CLI */
{
char *argv[NUMARGS]; /* Filled in by GADS() */
if(*argline != '\n')
{
if(GADS(argline,(LONG)strlen(argline),CLI_Help,argv,CLI_Template)>0)
{
if(argv[ARG_DELAY]) delay=Atol(argv[ARG_DELAY]);
loop = (BOOL)argv[ARG_LOOP];
all = (BOOL)argv[ARG_ALL];
nobreak = (BOOL)argv[ARG_NOBREAK];
overscan = (BOOL)!argv[ARG_NOOVERSCAN];
do
{
reg char **pattern=(char **)argv[ARG_PATTERN];
if(*pattern)
{
while(*pattern) ShowPattern(*pattern++);
}
else ShowPattern("*");
} while(loop);
}
else Fail(CLI_Help);
}
else Fail(CLI_Help);
}
else /* Called from Workbench */
{
reg struct WBStartup *startup = (struct WBStartup *)argline;
struct WBArg *arg;
reg WORD i;
if(startup->sm_NumArgs > 1) /* Started with some arguments */
{
arg = startup->sm_ArgList;
for(i=1; i<startup->sm_NumArgs; ++i)
{
arg++;
if(arg->wa_Lock) CurrentDir(arg->wa_Lock);
else Fail("Can't lock!");
if(arg->wa_Name && *arg->wa_Name) ShowPattern(arg->wa_Name);
else ShowPattern("*");
}
}
else
{
WBDelay=6291456; /* 6 seconds delay */
#ifdef GERMAN
Fail("Bitte klicken Sie alle gewünschten Bild-Dateien oder Schubladen bei ge-\n"
"drückter SHIFT-Taste an, klicken Sie danach 2x auf das ShowIFF-Piktogramm.");
#else
Fail("Please select all drawers and files to view while holding\n"
"down the SHIFT key, then double-click the ShowIFF icon.");
#endif
}
}
WBDelay=1048576; /* One second delay */
#ifdef GERMAN
Fail("Fertig.");
#else
Fail("All done.");
#endif
}